<!--
<template>
    <table cellspacing="0" cellpadding="0" border="0" :style="styleObject">
        <colgroup>
            <col v-for="(column, index) in columns" :width="setCellWidth(column)">
        </colgroup>
        <tbody :class="[prefixCls + '-tbody']">
            <template v-for="(row, index) in data">
                <table-tr
                    :draggable="draggable"
                    :row="row"
                    :key="rowKey ? row._rowKey : index"
                    :prefix-cls="prefixCls"
                    @mouseenter.native.stop="handleMouseIn(row._index)"
                    @mouseleave.native.stop="handleMouseOut(row._index)"
                    @click.native="clickCurrentRow(row._index)"
                    @dblclick.native.stop="dblclickCurrentRow(row._index)">
                    <td v-for="(column, colIndex) in columns" :class="alignCls(column, row)" v-bind="getSpan(row, column, index, colIndex)" v-if="showWithSpan(row, column, index, colIndex)">
                        <table-cell
                            :fixed="fixed"
                            :prefix-cls="prefixCls"
                            :row="row"
                            :key="column._columnKey"
                            :column="column"
                            :natural-index="index"
                            :index="row._index"
                            :checked="rowChecked(row._index)"
                            :disabled="rowDisabled(row._index)"
                            :expanded="rowExpanded(row._index)"
                        ></table-cell>
                    </td>
                </table-tr>
                <tr v-if="rowExpanded(row._index)" :class="{[prefixCls + '-expanded-hidden']: fixed}">
                    <td :colspan="columns.length" :class="prefixCls + '-expanded-cell'">
                        <Expand :key="rowKey ? row._rowKey : index" :row="row" :render="expandRender" :index="row._index"></Expand>
                    </td>
                </tr>
            </template>
        </tbody>
    </table>
</template>
-->
<script>
// todo :key="row"
import { h } from "vue";
import TableTr from "./table-tr.vue";
import TableCell from "./cell.vue";
import Expand from "./expand.js";
import Mixin from "./mixin";

export default {
    name: "TableBody",
    mixins: [Mixin],
    components: { TableCell, Expand, TableTr },
    props: {
        prefixCls: String,
        styleObject: Object,
        columns: Array,
        data: Array, // rebuildData
        objData: Object,
        columnsWidth: Object,
        fixed: {
            type: [Boolean, String],
            default: false,
        },
        draggable: {
            type: Boolean,
            default: false,
        },
        rowKey: {
            type: [Boolean, String],
            default: false,
        },
    },
    computed: {
        expandRender() {
            let render = function () {
                return "";
            };
            for (let i = 0; i < this.columns.length; i++) {
                const column = this.columns[i];
                if (column.type && column.type === "expand") {
                    if (column.render) render = column.render;
                }
            }
            return render;
        },
    },
    methods: {
        rowChecked(_index) {
            return this.objData[_index] && this.objData[_index]._isChecked;
        },
        rowDisabled(_index) {
            return this.objData[_index] && this.objData[_index]._isDisabled;
        },
        rowExpanded(_index) {
            return this.objData[_index] && this.objData[_index]._isExpanded;
        },
        rowStatusByRowKey(type, rowKey) {
            const data = this.$parent.getDataByRowKey(rowKey);
            return data[type];
        },
        handleMouseIn(_index, event, rowKey) {
            event.stopPropagation();
            this.$parent.handleMouseIn(_index, rowKey);
        },
        handleMouseOut(_index, event, rowKey) {
            event.stopPropagation();
            this.$parent.handleMouseOut(_index, rowKey);
        },
        clickCurrentRow(_index, event, rowKey) {
            this.$parent.clickCurrentRow(_index, rowKey);
        },
        dblclickCurrentRow(_index, event, rowKey) {
            event.stopPropagation();
            this.$parent.dblclickCurrentRow(_index, rowKey);
        },
        clickCell(row, column, key, event) {
            this.$parent.$emit("on-cell-click", row, column, row[key], event);
        },
        contextmenuCurrentRow(_index, event, rowKey) {
            event.stopPropagation();
            if (this.$parent.contextMenu) event.preventDefault();
            this.$parent.contextmenuCurrentRow(_index, rowKey, event);
        },
        selectStartCurrentRow() {
            if (this.$parent.contextMenu) {
                // event.stopPropagation();
                // event.preventDefault();
            }
        },
        getSpan(row, column, rowIndex, columnIndex) {
            const fn = this.$parent.spanMethod;
            if (typeof fn === "function") {
                const result = fn({
                    row,
                    column,
                    rowIndex,
                    columnIndex,
                });
                let rowspan = 1;
                let colspan = 1;
                if (Array.isArray(result)) {
                    rowspan = result[0];
                    colspan = result[1];
                } else if (typeof result === "object") {
                    rowspan = result.rowspan;
                    colspan = result.colspan;
                }
                return {
                    rowspan,
                    colspan,
                };
            } else {
                return {};
            }
        },
        showWithSpan(row, column, rowIndex, columnIndex) {
            const result = this.getSpan(row, column, rowIndex, columnIndex);
            return !(
                ("rowspan" in result && result.rowspan === 0) ||
                ("colspan" in result && result.colspan === 0)
            );
        },
        isTrShow(rowKey) {
            let status = true;
            let child;
            for (let i in this.objData) {
                const row = this.objData[i];
                const showChildren = row._isShowChildren;
                if (row._rowKey === rowKey) {
                    status = status && showChildren;
                    break;
                } else if (row.children && row.children.length) {
                    child = this.getTrStatus(
                        rowKey,
                        row,
                        status && showChildren
                    );
                    if (child[0] && child[0]._rowKey === rowKey) {
                        return child[1];
                    }
                }
            }
            return status;
        },
        getTrStatus(rowKey, data, parentStatus) {
            let status = parentStatus;
            let childData;
            if (data.children && data.children.length) {
                for (let i = 0; i < data.children.length; i++) {
                    const row = data.children[i];
                    const showChildren = row._isShowChildren;
                    if (row._rowKey === rowKey) {
                        childData = row;
                        status = status && showChildren;
                        break;
                    } else if (row.children && row.children.length) {
                        const child = this.getTrStatus(
                            rowKey,
                            row,
                            status && showChildren
                        );
                        if (child[0] && child[0]._rowKey === rowKey) {
                            return child;
                        }
                    }
                }
            }
            return [childData, status];
        },
        getLevel(rowKey) {
            let level;
            let child;
            for (let i = 0; i < this.data.length; i++) {
                const row = this.data[i];
                if (row[this.rowKey] === rowKey) {
                    level = 0;
                    break;
                } else if (row.children && row.children.length) {
                    child = this.getChildLevel(row, rowKey, 1);
                    if (child[0] && child[0][this.rowKey] === rowKey) {
                        return child[1];
                    }
                }
            }
            return level;
        },
        getChildLevel(data, rowKey, level) {
            let newLevel;
            let childData;
            if (data.children && data.children.length) {
                for (let i = 0; i < data.children.length; i++) {
                    const row = data.children[i];
                    if (row[this.rowKey] === rowKey) {
                        childData = row;
                        newLevel = level;
                        break;
                    } else if (row.children && row.children.length) {
                        const child = this.getChildLevel(
                            row,
                            rowKey,
                            level + 1
                        );
                        if (child[0] && child[0][this.rowKey] === rowKey) {
                            return child;
                        }
                    }
                }
            }
            return [childData, newLevel];
        },
        getChildNode(h, data, nodes) {
            if (data.children && data.children.length) {
                data.children.forEach((row, index) => {
                    let $tds = [];

                    this.columns.forEach((column, colIndex) => {
                        if (this.showWithSpan(row, column, index, colIndex)) {
                            const $tableCell = h(TableCell, {
                                fixed: this.fixed,
                                "prefix-cls": this.prefixCls,
                                row: row,
                                column: column,
                                "natural-index": index,
                                index: row._index,
                                checked: this.rowStatusByRowKey(
                                    "_isChecked",
                                    row._rowKey
                                ),
                                disabled: this.rowStatusByRowKey(
                                    "_isDisabled",
                                    row._rowKey
                                ),
                                expanded: this.rowStatusByRowKey(
                                    "_isExpanded",
                                    row._rowKey
                                ),
                                treeNode: true,
                                treeLevel: this.getLevel(row._rowKey),
                                key: column._columnKey,
                            });

                            const $td = h(
                                "td",
                                {
                                    class: this.alignCls(column, row),
                                    ...this.getSpan(
                                        row,
                                        column,
                                        index,
                                        colIndex
                                    ),
                                    onClick: (e) =>
                                        this.clickCell(
                                            row,
                                            column,
                                            column.key,
                                            e
                                        ),
                                },
                                [$tableCell]
                            );
                            $tds.push($td);
                        }
                    });

                    // 判断节点是否展开
                    const trStyle = {};
                    if (!this.isTrShow(data._rowKey)) trStyle.display = "none";

                    const $tableTr = h(
                        TableTr,
                        {
                            draggable: false,
                            row: row,
                            "prefix-cls": this.prefixCls,
                            isChildren: true,
                            style: trStyle,
                            key: this.rowKey ? row._rowKey : index,
                            onMouseenter: (e) =>
                                this.handleMouseIn(row._index, e, row._rowKey),
                            onMouseleave: (e) =>
                                this.handleMouseOut(row._index, e, row._rowKey),
                            onClick: (e) =>
                                this.clickCurrentRow(
                                    row._index,
                                    e,
                                    row._rowKey
                                ),
                            onDblclick: (e) =>
                                this.dblclickCurrentRow(
                                    row._index,
                                    e,
                                    row._rowKey
                                ),
                            onContextmenu: (e) =>
                                this.contextmenuCurrentRow(
                                    row._index,
                                    e,
                                    row._rowKey
                                ),
                            onSelectstart: (e) =>
                                this.selectStartCurrentRow(
                                    row._index,
                                    e,
                                    row._rowKey
                                ),
                        },
                        () => $tds
                    );

                    nodes.push($tableTr);

                    if (row.children && row.children.length) {
                        this.getChildNode(h, row, nodes);
                    }
                });
                return nodes;
            } else {
                return nodes;
            }
        },
    },
    render() {
        let $cols = [];
        this.columns.forEach((column) => {
            const $col = h("col", {
                width: this.setCellWidth(column),
            });
            $cols.push($col);
        });
        const $colgroup = h("colgroup", {}, $cols);

        let $tableTrs = [];
        this.data.forEach((row, index) => {
            let $tds = [];

            this.columns.forEach((column, colIndex) => {
                if (this.showWithSpan(row, column, index, colIndex)) {
                    const $tableCell = h(TableCell, {
                        fixed: this.fixed,
                        "prefix-cls": this.prefixCls,
                        row: row,
                        column: column,
                        "natural-index": index,
                        index: row._index,
                        checked: this.rowChecked(row._index),
                        disabled: this.rowDisabled(row._index),
                        expanded: this.rowExpanded(row._index),
                        key: column._columnKey,
                    });

                    const $td = h(
                        "td",
                        {
                            class: this.alignCls(column, row),
                            ...this.getSpan(row, column, index, colIndex),
                            onClick: (e) =>
                                this.clickCell(row, column, column.key, e),
                        },
                        [$tableCell]
                    );
                    $tds.push($td);
                }
            });

            const $tableTr = h(
                TableTr,
                {
                    draggable: this.draggable,
                    row: row,
                    "prefix-cls": this.prefixCls,
                    key: this.rowKey ? row._rowKey : index,
                    onMouseenter: (e) => this.handleMouseIn(row._index, e),
                    onMouseleave: (e) => this.handleMouseOut(row._index, e),
                    onClick: (e) => this.clickCurrentRow(row._index, e),
                    onDblclick: (e) => this.dblclickCurrentRow(row._index, e),
                    onContextmenu: (e) =>
                        this.contextmenuCurrentRow(row._index, e),
                    onSelectstart: (e) =>
                        this.selectStartCurrentRow(row._index, e),
                },
                () => $tds
            );
            $tableTrs.push($tableTr);

            // 可展开
            if (this.rowExpanded(row._index)) {
                const $Expand = h(Expand, {
                    row: row,
                    render: this.expandRender,
                    index: row._index,
                    key: this.rowKey ? row._rowKey : index,
                });
                const $td = h(
                    "td",
                    {
                        colspan: this.columns.length,
                        class: this.prefixCls + "-expanded-cell",
                    },
                    [$Expand]
                );
                const $tr = h(
                    "tr",
                    {
                        class: {
                            [this.prefixCls + "-expanded-hidden"]: this.fixed,
                        },
                    },
                    [$td]
                );
                $tableTrs.push($tr);
            }

            // 子数据
            if (row.children && row.children.length) {
                const $childNodes = this.getChildNode(h, row, []);
                $childNodes.forEach((item) => {
                    $tableTrs.push(item);
                });
            }
        });

        const $tbody = h(
            "tbody",
            {
                class: this.prefixCls + "-tbody",
            },
            [$tableTrs]
        );

        return h(
            "table",
            {
                cellspacing: "0",
                cellpadding: "0",
                border: "0",
                style: this.styleObject,
            },
            [$colgroup, $tbody]
        );
    },
};
</script>
